from selenium import webdriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from webdriver_manager.microsoft import EdgeChromiumDriverManager
import logging
import random
import time

class WebUtils:
    def __init__(self):
        self.driver = None
        self.wait = None
        self.logger = logging.getLogger(__name__)

    def create_browser(self, web_type="edge", silent_running=False):
        """创建浏览器实例"""
        try:
            options = webdriver.EdgeOptions()
            if silent_running:
                options.add_argument('--headless=new')
            
            # 添加更多随机的用户代理
            user_agents = [
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0"
            ]
            selected_ua = random.choice(user_agents)
            
            # 基础配置
            options.add_argument(f'user-agent={selected_ua}')
            options.add_argument('--disable-blink-features=AutomationControlled')
            options.add_experimental_option("excludeSwitches", ["enable-automation", "enable-logging"])
            options.add_experimental_option('useAutomationExtension', False)
            
            # 设置固定的窗口大小
            options.add_argument('--window-size=1366,768')
            
            # 添加更多性能和稳定性配置
            options.add_argument('--disable-gpu')
            options.add_argument('--no-sandbox')
            options.add_argument('--disable-dev-shm-usage')
            options.add_argument('--disable-infobars')
            options.add_argument('--disable-browser-side-navigation')
            options.add_argument('--disable-features=TranslateUI')
            options.add_argument('--disable-extensions')
            options.add_argument('--disable-notifications')
            options.add_argument('--disable-popup-blocking')
            
            # 随机化语言和时区设置
            languages = ['en-US,en;q=0.9', 'en-GB,en;q=0.9', 'en-CA,en;q=0.9']
            options.add_argument(f'--lang={random.choice(languages)}')
            options.add_argument('--disable-timezone-override')
            
            # 添加更多的浏览器参数
            options.add_argument('--disable-web-security')
            options.add_argument('--disable-site-isolation-trials')
            options.add_argument('--disable-features=IsolateOrigins,site-per-process')
            options.add_argument('--disable-blink-features')
            options.add_argument('--disable-blink-features=AutomationControlled')
            
            # 创建浏览器实例
            service = Service(EdgeChromiumDriverManager().install())
            self.driver = webdriver.Edge(service=service, options=options)
            
            # 执行CDP命令来修改浏览器指纹
            self.driver.execute_cdp_cmd('Network.setUserAgentOverride', {
                "userAgent": selected_ua,
                "platform": "Windows",
                "acceptLanguage": random.choice(languages),
                "platformVersion": "10.0.0"
            })
            
            # 注入反检测JavaScript
            self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
                "source": """
                    // 删除webdriver标记
                    delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array;
                    delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise;
                    delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol;
                    
                    // 修改navigator属性
                    const overrideNavigator = {
                        webdriver: undefined,
                        hardwareConcurrency: Math.floor(Math.random() * 8) + 4,
                        deviceMemory: Math.floor(Math.random() * 8) + 4,
                        platform: "Win32",
                        languages: ["en-US", "en"],
                        maxTouchPoints: Math.floor(Math.random() * 5),
                        vendor: "Google Inc.",
                        connection: {
                            downlink: Math.floor(Math.random() * 30) + 5,
                            effectiveType: ["4g", "3g"][Math.floor(Math.random() * 2)],
                            rtt: Math.floor(Math.random() * 100) + 50
                        }
                    };
                    
                    Object.keys(overrideNavigator).forEach(key => {
                        Object.defineProperty(navigator, key, {
                            get: () => overrideNavigator[key]
                        });
                    });
                    
                    // 随机化性能API
                    const originalNow = performance.now;
                    performance.now = function() {
                        return originalNow.call(performance) + Math.random() * 20;
                    };
                    
                    // 随机化Canvas指纹
                    const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
                    HTMLCanvasElement.prototype.toDataURL = function(type) {
                        if (type === 'image/png' && this.width === 220 && this.height === 30) {
                            return originalToDataURL.apply(this, arguments);
                        }
                        
                        const context = this.getContext('2d');
                        if (context) {
                            const imageData = context.getImageData(0, 0, this.width, this.height);
                            for(let i = 0; i < imageData.data.length; i += 4) {
                                imageData.data[i] += Math.floor(Math.random() * 5) - 2;
                                imageData.data[i+1] += Math.floor(Math.random() * 5) - 2;
                                imageData.data[i+2] += Math.floor(Math.random() * 5) - 2;
                            }
                            context.putImageData(imageData, 0, 0);
                        }
                        return originalToDataURL.apply(this, arguments);
                    };
                    
                    // 随机化WebGL
                    const getParameterProxyHandler = {
                        apply: function(target, ctx, args) {
                            const param = args[0];
                            const result = target.apply(ctx, args);
                            
                            const randomizeParams = {
                                37445: ['Intel Inc.', 'NVIDIA Corporation', 'AMD'][Math.floor(Math.random() * 3)],
                                37446: ['Intel(R) Iris(TM) Graphics', 'NVIDIA GeForce GTX', 'AMD Radeon'][Math.floor(Math.random() * 3)],
                                34047: [16384, 32768, 8192][Math.floor(Math.random() * 3)],
                                35661: [32, 64, 128][Math.floor(Math.random() * 3)],
                                34076: [16384, 32768, 8192][Math.floor(Math.random() * 3)]
                            };
                            
                            return randomizeParams[param] || result;
                        }
                    };
                    
                    if (WebGLRenderingContext.prototype.getParameter) {
                        WebGLRenderingContext.prototype.getParameter = new Proxy(WebGLRenderingContext.prototype.getParameter, getParameterProxyHandler);
                    }
                    
                    // 随机化音频指纹
                    const audioContext = window.AudioContext || window.webkitAudioContext;
                    if (audioContext) {
                        const originalGetChannelData = AudioBuffer.prototype.getChannelData;
                        AudioBuffer.prototype.getChannelData = function() {
                            const channelData = originalGetChannelData.apply(this, arguments);
                            for(let i = 0; i < channelData.length; i += 100) {
                                channelData[i] += Math.random() * 0.0001;
                            }
                            return channelData;
                        };
                    }
                    
                    // 随机化字体指纹
                    const originalMeasureText = CanvasRenderingContext2D.prototype.measureText;
                    CanvasRenderingContext2D.prototype.measureText = function() {
                        const result = originalMeasureText.apply(this, arguments);
                        result.width += Math.random() * 0.1;
                        return result;
                    };
                    
                    // 模拟真实的DOM操作延迟
                    const originalCreateElement = document.createElement;
                    document.createElement = function() {
                        const start = performance.now();
                        const element = originalCreateElement.apply(this, arguments);
                        const delay = Math.random() * 2;
                        while (performance.now() - start < delay) {}
                        return element;
                    };
                    
                    // 模拟真实的事件处理
                    const originalAddEventListener = EventTarget.prototype.addEventListener;
                    EventTarget.prototype.addEventListener = function(type, listener, options) {
                        const wrappedListener = function(event) {
                            const delay = Math.random() * 5;
                            setTimeout(() => {
                                listener.call(this, event);
                            }, delay);
                        };
                        return originalAddEventListener.call(this, type, wrappedListener, options);
                    };
                    
                    // 修改Selenium标记
                    Object.defineProperty(navigator, 'selenium', {
                        get: () => undefined
                    });
                    
                    // 修改自动化标记
                    Object.defineProperty(navigator, 'webdriver', {
                        get: () => false
                    });
                    
                    // 添加真实的浏览器功能
                    window.chrome = {
                        app: {
                            isInstalled: false,
                            InstallState: {
                                DISABLED: 'DISABLED',
                                INSTALLED: 'INSTALLED',
                                NOT_INSTALLED: 'NOT_INSTALLED'
                            },
                            RunningState: {
                                CANNOT_RUN: 'CANNOT_RUN',
                                READY_TO_RUN: 'READY_TO_RUN',
                                RUNNING: 'RUNNING'
                            }
                        },
                        runtime: {
                            OnInstalledReason: {
                                CHROME_UPDATE: 'chrome_update',
                                INSTALL: 'install',
                                SHARED_MODULE_UPDATE: 'shared_module_update',
                                UPDATE: 'update'
                            },
                            OnRestartRequiredReason: {
                                APP_UPDATE: 'app_update',
                                OS_UPDATE: 'os_update',
                                PERIODIC: 'periodic'
                            },
                            PlatformArch: {
                                ARM: 'arm',
                                ARM64: 'arm64',
                                MIPS: 'mips',
                                MIPS64: 'mips64',
                                X86_32: 'x86-32',
                                X86_64: 'x86-64'
                            },
                            PlatformNaclArch: {
                                ARM: 'arm',
                                MIPS: 'mips',
                                MIPS64: 'mips64',
                                X86_32: 'x86-32',
                                X86_64: 'x86-64'
                            },
                            PlatformOs: {
                                ANDROID: 'android',
                                CROS: 'cros',
                                LINUX: 'linux',
                                MAC: 'mac',
                                OPENBSD: 'openbsd',
                                WIN: 'win'
                            },
                            RequestUpdateCheckStatus: {
                                NO_UPDATE: 'no_update',
                                THROTTLED: 'throttled',
                                UPDATE_AVAILABLE: 'update_available'
                            }
                        }
                    };
                    
                    // 添加电池API
                    if (navigator.getBattery) {
                        const originalGetBattery = navigator.getBattery;
                        navigator.getBattery = function() {
                            return new Promise((resolve) => {
                                originalGetBattery.call(navigator).then(battery => {
                                    const fakeBattery = {
                                        charging: Math.random() > 0.5,
                                        chargingTime: Math.floor(Math.random() * 3600),
                                        dischargingTime: Math.floor(Math.random() * 3600),
                                        level: Math.random()
                                    };
                                    resolve(fakeBattery);
                                });
                            });
                        };
                    }
                    
                    // 添加真实的错误处理
                    window.onerror = function(msg, url, line, col, error) {
                        return false;
                    };
                    
                    // 添加真实的控制台行为
                    const consoleAPI = {
                        log: console.log,
                        warn: console.warn,
                        error: console.error,
                        info: console.info,
                        debug: console.debug
                    };
                    
                    Object.keys(consoleAPI).forEach(key => {
                        console[key] = function() {
                            if (arguments[0] === '%c') return;
                            return consoleAPI[key].apply(console, arguments);
                        };
                    });
                """
            })
            
            # 随机化窗口位置
            self.driver.set_window_position(
                random.randint(0, 100),
                random.randint(0, 100)
            )
            
            # 设置超时
            self.driver.set_page_load_timeout(30)
            self.driver.set_script_timeout(30)
            
            # 创建等待对象
            self.wait = WebDriverWait(self.driver, 20)
            
            return self.driver
            
        except Exception as e:
            self.logger.error(f"创建浏览器失败: {str(e)}")
            raise

    def element_click(self, element_selector, timeout=6, simulate=True, move_mouse=False, 
                     anchor_type="center", offset_x=0, offset_y=0):
        """点击元素"""
        try:
            # 等待元素可见和可点击
            element = self.wait.until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, element_selector))
            )
            
            # 直接点击
            element.click()
            time.sleep(random.uniform(0.8, 1.5))
            return True
            
        except Exception as e:
            self.logger.error(f"点击元素失败: {str(e)}")
            return False

    def get_mouse_position(self):
        """获取当前鼠标位置"""
        try:
            position = self.driver.execute_script("""
                return [
                    window.screenX + window.outerWidth / 2,
                    window.screenY + window.outerHeight / 2
                ];
            """)
            return position[0], position[1]
        except Exception:
            return 0, 0

    def element_input(self, element_selector, text, append=False, simulate=True):
        """输入文本"""
        try:
            element = self.wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, element_selector))
            )
            if not append:
                element.clear()
            if simulate:
                for char in text:
                    element.send_keys(char)
                    time.sleep(random.uniform(0.1, 0.3))
            else:
                element.send_keys(text)
            return True
        except Exception as e:
            self.logger.error(f"输入文本失败: {str(e)}")
            return False

    def get_element_text(self, element_selector, timeout=10):
        """获取元素文本"""
        try:
            element = self.wait.until(
                EC.presence_of_element_located((By.CSS_SELECTOR, element_selector))
            )
            return element.text
        except Exception as e:
            self.logger.error(f"获取元素文本失败: {str(e)}")
            return None

    def close_browser(self):
        """关闭浏览器"""
        if self.driver:
            self.driver.quit()
            self.driver = None
            self.wait = None

    def wait_for_page_load(self, timeout=30):
        """等待页面加载完成"""
        try:
            # 等待页面状态为complete
            self.wait.until(
                lambda driver: driver.execute_script("return document.readyState") == "complete"
            )
            
            # 等待一小段时间让页面稳定
            time.sleep(2)
            
            return True
        except Exception as e:
            self.logger.error(f"等待页面加载超时: {str(e)}")
            return False

    def wait_for_elements(self, by, selector, timeout=20):
        """等待多个元素出现"""
        try:
            wait = WebDriverWait(self.driver, timeout)
            elements = wait.until(
                EC.presence_of_all_elements_located((by, selector))
            )
            return elements
        except Exception as e:
            self.logger.warning(f"等待元素出现超时: {str(e)}")
            return []

    def wait_for_element(self, by, selector, timeout=20):
        """等待单个元素出现"""
        try:
            wait = WebDriverWait(self.driver, timeout)
            element = wait.until(
                EC.presence_of_element_located((by, selector))
            )
            return element
        except Exception as e:
            self.logger.error(f"等待元素出现超时: {str(e)}")
            raise

    def check_and_close_feedback(self) -> bool:
        """
        检查并关闭反馈弹窗
        :return: 是否成功处理反馈弹窗
        """
        try:
            # 等待页面加载完成
            self.wait_for_page_load()
            
            # 检查所有可能的反馈弹窗类型
            feedback_selectors = [
                "//div[contains(text(), 'We want to hear how we can improve your experience')]",
                "//div[contains(@class, 'fsrFeedback')]",
                "//div[contains(@class, 'uws-modal__header')]",
                "//div[contains(@class, 'modal-header')]",
                "//div[contains(@class, 'feedback-modal')]",
                "//iframe[contains(@id, 'fsrFeedback')]"
            ]
            
            # 检查并切换到反馈iframe（如果存在）
            try:
                iframes = self.driver.find_elements(By.TAG_NAME, "iframe")
                for iframe in iframes:
                    if "feedback" in iframe.get_attribute("id").lower():
                        self.driver.switch_to.frame(iframe)
                        break
            except Exception:
                pass
            
            # 检查所有可能的反馈弹窗
            for selector in feedback_selectors:
                try:
                    dialogs = self.driver.find_elements(By.XPATH, selector)
                    if dialogs and dialogs[0].is_displayed():
                        self.logger.info(f"发现反馈弹窗: {selector}")
                        
                        # 尝试多种方式关闭弹窗
                        close_buttons = [
                            "//div[text()='No thanks']/..",
                            "//button[contains(text(), 'No thanks')]",
                            "//button[contains(@class, 'decline')]",
                            "//button[contains(@class, 'close')]",
                            "//div[contains(@class, 'close-button')]",
                            "//span[contains(@class, 'close')]"
                        ]
                        
                        for btn_selector in close_buttons:
                            try:
                                close_btns = self.driver.find_elements(By.XPATH, btn_selector)
                                if close_btns and close_btns[0].is_displayed():
                                    # 尝试三种不同的点击方式
                                    try:
                                        # 方式1: 直接点击
                                        close_btns[0].click()
                                    except:
                                        try:
                                            # 方式2: JavaScript点击
                                            self.driver.execute_script("arguments[0].click();", close_btns[0])
                                        except:
                                            # 方式3: 移除元素
                                            self.driver.execute_script("""
                                                var elements = document.evaluate(
                                                    arguments[0],
                                                    document,
                                                    null,
                                                    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
                                                    null
                                                );
                                                for(var i = 0; i < elements.snapshotLength; i++) {
                                                    var element = elements.snapshotItem(i);
                                                    if(element) {
                                                        element.parentNode.removeChild(element);
                                                    }
                                                }
                                            """, selector)
                                    
                                    # 等待弹窗消失
                                    time.sleep(1)
                                    
                                    # 验证弹窗是否真的关闭
                                    if not dialogs[0].is_displayed():
                                        self.logger.info("成功关闭反馈弹窗")
                                        break
                            except Exception as e:
                                self.logger.debug(f"尝试关闭按钮 {btn_selector} 失败: {str(e)}")
                                continue
                except Exception:
                    continue
            
            # 切回主框架
            try:
                self.driver.switch_to.default_content()
            except Exception:
                pass
            
            # 强制移除所有可能的遮罩层
            self.driver.execute_script("""
                function removeElements(selector) {
                    var elements = document.querySelectorAll(selector);
                    elements.forEach(function(element) {
                        if(element && element.style.display !== 'none') {
                            element.style.display = 'none';
                        }
                    });
                }
                
                // 移除常见的遮罩和弹窗类
                removeElements('.modal');
                removeElements('.modal-backdrop');
                removeElements('.overlay');
                removeElements('.feedback-modal');
                removeElements('.fsrFeedback');
                removeElements('.uws-modal__header');
                removeElements('.uws-modal');
                
                // 移除body的modal相关类
                document.body.classList.remove('modal-open');
                document.body.style.overflow = '';
                document.body.style.paddingRight = '';
            """)
            
            return True
            
        except Exception as e:
            self.logger.debug(f"检查反馈弹窗时出现异常: {str(e)}")
            return False

    def check_captcha_failure(self) -> bool:
        """
        检查是否出现人机验证失败
        :return: 是否出现验证失败
        """
        try:
            # 检查验证失败弹窗
            failure_dialog = self.driver.find_elements(
                By.XPATH,
                "//div[contains(text(), 'That didn't work')]"
            )
            
            if failure_dialog and failure_dialog[0].is_displayed():
                self.logger.warning("检测到人机验证失败...")
                # 查找并点击"Start new session"按钮
                start_new = self.wait.until(
                    EC.element_to_be_clickable((
                        By.XPATH,
                        "//button[contains(text(), 'Start new session')]"
                    ))
                )
                if start_new:
                    start_new.click()
                    time.sleep(2)  # 等待页面刷新
                    self.logger.info("已点击开始新会话按钮")
                return True
                
            return False
            
        except Exception as e:
            self.logger.debug(f"检查人机验证失败时出现异常: {str(e)}")
            return False 